package com.gzhryc.common.xml;

import com.gzhryc.common.ClassTools;
import com.gzhryc.common.StringTools;
import com.gzhryc.common.xml.annotation.XmlAttribute;
import com.gzhryc.common.xml.annotation.XmlElement;
import com.gzhryc.common.xml.annotation.XmlText;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Attribute;
import org.jsoup.nodes.Attributes;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

public class HtmlTools {

    /**
     * 解析X字符串为一个对象
     *
     * @param html
     * @param clazz
     * @return
     */
    public static <T> T changToObject(String html, Class<T> clazz) {
        try {
            Document doc = Jsoup.parse(html);
            Element root = doc.root();
            T entity = clazz.newInstance();

            //设置标签名称
            String typeName = null;
            XmlElement xmlEl = clazz.getAnnotation(XmlElement.class);
            if (xmlEl != null && StringTools.isNotBlank(xmlEl.typeName())) {
                typeName = xmlEl.typeName();
            }
            Field[] fields = ClassTools.getDeclaredFields(clazz);
            Map<String, List<Object>> values = new HashMap<>();      //List属性
            getElement(root, entity, fields, values,typeName);
            //设置List属性
            for(Field field : fields){
                if (List.class.equals(field.getType())) {
                    List<Object> value = values.get(field.getName());
                    if(value != null){
                        field.setAccessible(true);
                        field.set(entity, value);
                    }
                }
            }
            return entity;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 递归获取节点属性并赋予给对象的相应属性
     *
     * @param element
     * @param entity
     * @param fields
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private static void getElement(Element element, Object entity, Field[] fields, Map<String,List<Object>> values,String typeName)
            throws InstantiationException, IllegalAccessException {
        //属性
        Attributes attributes = element.attributes();
        if (attributes != null && attributes.size() > 0) {
           Iterator<Attribute> iterator = attributes.iterator();
            while (iterator.hasNext()) {
                Attribute attribute = iterator.next();
                for (Field field : fields) {
                    if (Modifier.isStatic(field.getModifiers())) {
                        continue;
                    }

                    String name = field.getName();
                    XmlAttribute xmlAttr = field.getAnnotation(XmlAttribute.class);
                    if(xmlAttr != null){
                        name = xmlAttr.value();
                    }

                    if(attribute.getKey().equals(name)){
                        if(ClassTools.isBaseType(field.getType())){
                            String typeValue = attribute.getValue();
                            ClassTools.setFieldValue(entity, field, typeValue);
                        }
                        break;
                    }
                }
            }
        }

        //标签里的内容
        for (Field field : fields) {
            if (Modifier.isStatic(field.getModifiers())) {
                continue;
            }
            XmlText xmlText = field.getAnnotation(XmlText.class);
            if(xmlText != null){
                if(ClassTools.isBaseType(field.getType())){
                    ClassTools.setFieldValue(entity, field, element.wholeOwnText());
                }
            }
        }

        //检查是否有自动匹配
        Field autoField = null;
        List<Field> nodeFieldList = new ArrayList<>();
        for (Field field : fields) {
            if (Modifier.isStatic(field.getModifiers())) {
                continue;
            }
            field.setAccessible(true);
            XmlElement xmlEl = field.getAnnotation(XmlElement.class);
            if (xmlEl != null) {
                boolean flag = true;
                for(String name : xmlEl.value()) {
                    if ("*".equals(name)) {
                        autoField = field;
                        flag = false;
                        break;
                    }
                }
                if(flag){
                    nodeFieldList.add(field);
                }
            }else if(StringTools.isNotBlank(typeName)){
                //设置标签名称
                if(typeName.equals(field.getName())){
                    if(ClassTools.isBaseType(field.getType())){
                        String typeValue = element.nodeName();
                        ClassTools.setFieldValue(entity, field, typeValue);
                    }
                }
            }
        }

        Elements elements = element.children();
        if (elements != null) {
            for(int i = 0;i<elements.size();i++){
                Element childEl = elements.get(i);
                boolean flag = false;
                for (Field field : nodeFieldList) {
                    field.setAccessible(true);
                    XmlElement xmlEl = field.getAnnotation(XmlElement.class);
                    if (xmlEl != null) {
                        if(xmlEl.value().length == 0){
                            String name = field.getName();
                            if (name.equals(childEl.nodeName())) {
                                //匹配成功
                                setFieldValue(childEl,entity,field,values);
                                flag = true;
                                break;  //设置成功，跳出fields循环
                            }
                        }else {
                            for (String name : xmlEl.value()) {
                                // 获取节点名称
                                if (StringUtils.isNotBlank(name)) {
                                    if (name.equals(childEl.nodeName())) {
                                        //匹配成功
                                        setFieldValue(childEl,entity,field,values);
                                        flag = true;
                                        break;
                                    }
                                }
                            }
                            if(flag){
                                break;  //设置成功，跳出fields循环
                            }
                        }
                    }
                }

                if(!flag){
                    //未设置成功，检查是否有自动
                    if(autoField != null){
                        setFieldValue(childEl,entity,autoField,values);
                    }
                }
            }
        }
    }

    private static void setFieldValue(Element element, Object entity, Field field, Map<String,List<Object>> values) throws InstantiationException, IllegalAccessException {
        if (List.class.equals(field.getType())) {
            Class<?> genericClass = null;
            Type fc = field.getGenericType();
            // 是否是泛型参数类型
            if (fc != null && fc instanceof ParameterizedType) {
                ParameterizedType pt = (ParameterizedType) fc;
                genericClass = (Class<?>) pt.getActualTypeArguments()[0];
            }

            List<Object> value = values.get(field.getName());
            if(value == null){
                value = new ArrayList<>();
                values.put(field.getName(),value);
            }

            //List.add()
            if (ClassTools.isBaseType(genericClass)) {       //基础数据类型
                value.add(element.html());
            } else {
                Object childObj = genericClass.newInstance();
                String childTypeName = null;
                XmlElement xmlEl = genericClass.getAnnotation(XmlElement.class);
                if (xmlEl != null && StringTools.isNotBlank(xmlEl.typeName())) {
                    childTypeName = xmlEl.typeName();
                }
                Field[] fieldList = ClassTools.getDeclaredFields(genericClass);
                Map<String,List<Object>> childValues = new HashMap<>();     //子节点的List属性
                getElement(element, childObj, fieldList, childValues,childTypeName);
                //设置List属性
                for(Field childField : fieldList){
                    if (List.class.equals(childField.getType())) {
                        List<Object> childValue = childValues.get(childField.getName());
                        if(childValue != null){
                            childField.setAccessible(true);
                            childField.set(childObj, childValue);
                        }
                    }
                }
                value.add(childObj);
            }
        } else {
            Object childObj = field.getType().newInstance();
            String childTypeName = null;
            XmlElement xmlEl = field.getType().getAnnotation(XmlElement.class);
            if (xmlEl != null && StringTools.isNotBlank(xmlEl.typeName())) {
                childTypeName = xmlEl.typeName();
            }
            Field[] fieldList = ClassTools.getDeclaredFields(field.getType());
            Map<String,List<Object>> childValues = new HashMap<>();     //子节点的List属性
            getElement(element, childObj, fieldList, values,childTypeName);
            //设置List属性
            for(Field childField : fieldList){
                if (List.class.equals(childField.getType())) {
                    List<Object> childValue = childValues.get(childField.getName());
                    if(childValue != null){
                        childField.setAccessible(true);
                        childField.set(childObj, childValue);
                    }
                }
            }
            field.set(entity, childObj);
        }
    }
}
